////////////////////////////////////////////////////////////////////
// File:	AnimationManager.h
// Purpose: Encapsulates all animations used in the game by either
//			reusing or loading new animations based on a file.
//			Stores data related to an animation.
// Author:	Jay Baird
////////////////////////////////////////////////////////////////////

#ifndef ANIMATIONMANAGER_H
#define ANIMATIONMANAGER_H

#include "Animation.h"

#include <vector>
#include <deque>

#ifndef MAX_PATH
#define MAX_PATH 260
#endif

class Interpolator;
class AnimationManager
{
	friend Interpolator;

public:
	struct animInfo
	{
		bool used;
		char fileName[MAX_PATH];
		Animation anim;

		animInfo() : used(true) { fileName[0] = '\0'; }
		animInfo(char* _fileName) : used(true) { if(_fileName) strcpy_s(fileName, strlen(_fileName) + 1, _fileName); }
	};

	typedef struct KeyFrameRange
	{
		unsigned begin;
		unsigned end;

		KeyFrameRange() : begin(-1), end(-1) { }
		KeyFrameRange(unsigned _begin, unsigned _end) : begin(_begin), end(_end) { }

	} Range;

private:
	std::vector<animInfo> m_animations;	// Animations storing information directly about an animation (KeyFrames)

	static AnimationManager m_instance;

	AnimationManager();
	~AnimationManager();
	AnimationManager(const AnimationManager&);
	AnimationManager& operator=(const AnimationManager&);

	// Checks to see if an animation is already loaded into the manager
	// Ins: (fileName): the file to be loaded if the animation isn't found
	// Outs: None
	// Return: index of the found animation
	int FindAnimation(const char* fileName) const;

public:
	static AnimationManager* GetInstance() { return &m_instance; }

	bool IsAvailable(int id) const
	{
		if(id < 0 || id >= (int)m_animations.size() || !m_animations[id].used) 
			return false;
		return true;
	}

	// Loads a specified animation from a file and attaches it to a meshID
	// Ins: (fileName): the file to be loaded from
	//		(meshID): the meshID to attach the animation to
	// Outs: None
	// Return: index for which the animation is located at, use this for the interpolator
	int Load(const char* fileName, int meshID);
	int Load(const std::string& fileName, int meshID)
	{
		return Load(fileName.c_str(), meshID);
	}

	// Splits a specified animation currently loaded into multiple animations based mainly on keyFrames
	// Ins: (id): animation index to split
	//	   (keyFrameRanges): keyFrameRanges in order to split the specific animation,
	//						 a Range is two ints (first int: start keyFrame, second int: end KeyFrame
	//	   (keyFrameRangeCount): amount of ranges inside the keyFrameRanges variable
	//
	// Outs: (indices): index(s) for which the new animations are at for use in the interpolator
	// Return: true/false whether or not the split had occured successfully on an animation id
	// Special Note: This function DOES NOT remove keyFrames from the animation being split on (id)
	bool Split(int id, std::deque<int>& indices, Range* keyFrameRanges, unsigned keyFrameRangeCount);

	// Removes an animation related to the ID
	// Ins: (id): animation index/id to remove
	// Outs: None
	// Return: true if removed successfully else false
	bool Remove(int id);

	// Removes all animations in the animationManager
	// Ins: None
	// Outs: None
	// Return: None
	void RemoveAll();

	float GetDuration(int id) const
	{
		if(!IsAvailable(id)) return 0.0f;
		return m_animations[id].anim.GetDuration();
	}
};

// H specific Functions //
// Flattens an animation keyframe and the matrices/bones associated
void TraverseKeyFrame(unsigned index, const MeshComponent::Bone* pBones, AnimationComponent::KeyFrame& frame);
///////////////////////////

#endif